package com.ajieee.merge.runner.finance;

import com.ajieee.merge.entity.finance.po.EtlManagerPO;
import com.ajieee.merge.enums.finance.EtlType;
import com.ajieee.merge.mapper.EtlManagerMapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;

/**
 * @author ajieee
 * @date 2025-10-02
 */
@Slf4j
@Getter
@RequiredArgsConstructor
public abstract class AbstractEtl {

	private LocalDate tradeDate;

	private final ThreadLocal<EtlContext> context = ThreadLocal.withInitial(EtlContext::new);

	@Autowired
	private EtlManagerMapper etlManagerMapper;

	/**
	 * 是否需要执行
	 */
	public boolean needExecute(LocalDate date) {
		this.tradeDate = date;

		Wrapper<EtlManagerPO> wrapper = Wrappers.<EtlManagerPO>lambdaQuery()
				.eq(EtlManagerPO::getDataDate, tradeDate)
				.eq(EtlManagerPO::getEtlType, getType());
		EtlManagerPO existed = etlManagerMapper.selectOne(wrapper);
		this.context.get().setExisted(existed);

		return existed == null || existed.getResult() != 1;
	}

	public void preExecute() {
		log.info("开始执行【{}】", getType().getName());
	}

	public abstract void doExecute();

	public void postExecute(Exception ex) {
		EtlManagerPO po = new EtlManagerPO();
		po.setEtlType(getType());
		po.setDuration(context.get().getDuration());
		po.setResult(ex != null ? 0 : 1);
		po.setDetail(ex != null ? ex.getMessage() : null);

		EtlManagerPO existed = context.get().getExisted();
		if (existed != null) {
			po.setId(existed.getId());
		} else {
			po.setExecuteCnt(1);
			po.setDataDate(tradeDate);
		}
		etlManagerMapper.insertOrUpdate(po);

		log.info("结束执行【{}】", getType().getName());
	}

	@Transactional(rollbackFor = Exception.class)
	public void execute() {
		preExecute();
		long start = System.currentTimeMillis();
		Exception ex = null;
		try {
			doExecute();
		} catch (Exception e) {
			ex = e;
			log.error("执行失败【{}】", getType().getName());
		} finally {
			EtlContext context = this.context.get();
			context.setDuration(System.currentTimeMillis() - start);
		}
		postExecute(ex);
	}

	public abstract EtlType getType();

}
